﻿using System.Linq;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using FluentUnity.Conventions;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FluentUnity.Tests.Dependencies
{
    /// <summary>
    /// Summary description for UnityConventionTest
    /// </summary>
    [TestClass]
    public class DependencyTests
    {
        [TestMethod]
        public void ConventionOnlyResolves()
        {
            UnityConvention conventions = new UnityConvention();
            var container = new UnityContainer();
            foreach (var ass in GetAssemblies())
                conventions.AddAssembly(ass);
            conventions.ApplyTo(container);

            var thing = container.Resolve<ISomeThing>();
            Assert.IsNotNull(thing);
            Assert.IsInstanceOfType(thing, typeof(SomeThing));
            Assert.IsNotNull(thing.SomeOtherThing);
            Assert.IsInstanceOfType(thing.SomeOtherThing, typeof(SomeOtherThing));
            thing.DoSomething();
        }

        [TestMethod]
        public void LoggingExecutes()
        {
            UnityConvention conventions = new UnityConvention();
            var logMessages = new List<string>();
            conventions.Log += logMessages.Add;
            var container = new UnityContainer();
            foreach (var ass in GetAssemblies())
                conventions.AddAssembly(ass);
            conventions.ApplyTo(container);

            Assert.AreNotEqual(0, logMessages.Count);
            foreach (var message in logMessages)
            {
                Console.WriteLine("Message: {0}", message);
            }
        }

        [TestMethod]
        public void EmptyUsesSomeOtherThing()
        {
            UnityConvention conventions = new UnityConvention();
            var container = new UnityContainer();
            foreach (var ass in GetAssemblies())
                conventions.AddAssembly(ass);
            conventions.ApplyTo(container);
            container.LoadConfiguration("empty");

            var thing = container.Resolve<ISomeThing>();
            Assert.IsNotNull(thing);
            Assert.IsInstanceOfType(thing, typeof(SomeThing));
            Assert.IsNotNull(thing.SomeOtherThing);
            Assert.IsInstanceOfType(thing.SomeOtherThing, typeof(SomeOtherThing));
            thing.DoSomething();
        }

        private IEnumerable<Assembly> GetAssemblies()
        {
            //yield return typeof(UnityConvention).Assembly;
            yield return typeof(DependencyTests).Assembly;
        }

        [TestMethod]
        //[ExpectedException(typeof(AssertFailedException))]
        public void OverriddenConfigFirstFails()
        {
            //ugly hack.  Resharper test runner doesn't honor ExpectedException for 3.5 Test Projects
            try
            {
                UnityConvention conventions = new UnityConvention();
                var container = new UnityContainer();
                container.LoadConfiguration("overridden");
                foreach (var ass in GetAssemblies())
                    conventions.AddAssembly(ass);
                conventions.ApplyTo(container);

                var thing = container.Resolve<ISomeThing>();
                Assert.IsNotNull(thing);
                Assert.IsInstanceOfType(thing, typeof(SomeThing));
                Assert.IsNotNull(thing.SomeOtherThing);
                Assert.IsInstanceOfType(thing.SomeOtherThing, typeof(SomeAlternateThing));
                thing.DoSomething();
                throw new Exception("Expected AssertFailedException");
            }
            catch (AssertFailedException)
            {
            }
        }

        [TestMethod]
        public void OverriddenUsesSomeAlternateThing()
        {
            UnityConvention conventions = new UnityConvention();
            var container = new UnityContainer();
            foreach (var ass in GetAssemblies())
                conventions.AddAssembly(ass);
            conventions.ApplyTo(container);
            container.LoadConfiguration("overridden");

            var thing = container.Resolve<ISomeThing>();
            Assert.IsNotNull(thing);
            Assert.IsInstanceOfType(thing, typeof(SomeThing));
            Assert.IsNotNull(thing.SomeOtherThing);
            Assert.IsInstanceOfType(thing.SomeOtherThing, typeof(SomeAlternateThing));
            thing.DoSomething();
        }
    }
}